#ifndef LOGGER_H
#define LOGGER_H

#include <functional>

#include "LogStream.hpp"
#include "Timestamp.h"

namespace Logger
{
    class Logger
    {
    public:
        enum class LogLevel
        {
            // TRACE,
            DEBUG,
            INFO, // 一般默认
            WARN,
            ERROR,
            FATAL, // CRITICAL
        };

        Logger(LogLevel logLevel, const char *fileName, int lineNum);
        ~Logger();

        // 默认fwrite()，fflush()到标准输出流
        static void defaultOutputFunc(const char *log, int len);
        static void defaultFlushFunc();
        // 用户可以调用set()传入自定义的回调，回调里是用户期望输出/刷新的位置如文件
        using OutputFunc = std::function<void(const char *, int)>;
        using FlushFunc = std::function<void()>;
        static void setOutputFunc(const OutputFunc &outputFunc);
        static void setFlushFunc(const FlushFunc &flushFunc);

        LogStream &getStream()
        {
            return this->impl_.stream_;
        }
        // 用户可以配置日志级别，>=级别才输出，默认INFO
        static void setLogLevel(Logger::LogLevel logLevel);
        static Logger::LogLevel getLogLevel();

    private:
        class Impl
        {
        public:
            // using LogLevel = Logger::LogLevel;
            Impl(LogLevel logLevel, const char *fileName, int lineNum);

            // 内部类成员直接公有权限
            Timestamp timestamp_;
            LogLevel logLevel_;
            const char *fileName_;
            int lineNum_;
            LogStream stream_;

            void formatTimestamp();
            static thread_local char sThreadTimestamp[64]; // 线程局部时间戳
            static thread_local time_t sThreadlastSeconds; // 上次格式化时间（秒）

            const char *toLogLevelName(LogLevel logLevel);
            const char *parseFileName();
        };

    private:
        Impl impl_;
    };
} // namespace Logger

// 预定义宏简化用户调用，用户可以配置日志级别，>=级别才输出，默认INFO
#define LOG_DEBUG                                                         \
    if (Logger::Logger::getLogLevel() <= Logger::Logger::LogLevel::DEBUG) \
    Logger::Logger(Logger::Logger::LogLevel::DEBUG, __FILE__, __LINE__).getStream()
#define LOG_INFO                                                         \
    if (Logger::Logger::getLogLevel() <= Logger::Logger::LogLevel::INFO) \
    Logger::Logger(Logger::Logger::LogLevel::INFO, __FILE__, __LINE__).getStream()
#define LOG_WARN                                                         \
    if (Logger::Logger::getLogLevel() <= Logger::Logger::LogLevel::WARN) \
    Logger::Logger(Logger::Logger::LogLevel::WARN, __FILE__, __LINE__).getStream()
#define LOG_ERROR                                                         \
    if (Logger::Logger::getLogLevel() <= Logger::Logger::LogLevel::ERROR) \
    Logger::Logger(Logger::Logger::LogLevel::ERROR, __FILE__, __LINE__).getStream()
#define LOG_FATAL                                                         \
    if (Logger::Logger::getLogLevel() <= Logger::Logger::LogLevel::FATAL) \
    Logger::Logger(Logger::Logger::LogLevel::FATAL, __FILE__, __LINE__).getStream()

#endif // LOGGER_H